#!/bin/bash
#
#  Copyright (c) 2020, The OpenThread Authors.
#  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
#  1. Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#  2. Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#  3. Neither the name of the copyright holder nor the
#     names of its contributors may be used to endorse or promote products
#     derived from this software without specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#  POSSIBILITY OF SUCH DAMAGE.
#

# Keep folder information
if [[ -n ${BASH_SOURCE[0]} ]]; then
    script_path="${BASH_SOURCE[0]}"
else
    script_path="$0"
fi

script_dir="$(dirname "$(realpath "$script_path")")"
repo_dir="$(dirname "$script_dir")"

source "$script_dir"/common_utility

###################################################################################################
#
# Utilities
#
###################################################################################################
die()
{
    echo " ** ERROR: $1"
    exit 1
}

available_boards_load()
{
    mapfile -t "$1" < <(find "$2"/ -mindepth 1 -maxdepth 1 -type d -name "*$3*" -printf "%f\n")
}

available_apps_load()
{
    IFX_APPS=("cli" "ncp" "rcp")
    echo "Available apps: ${IFX_APPS[*]}"
}

build_cli_uart()
{
    # Create the output folder
    builddir="${OT_CMAKE_BUILD_DIR:-$repo_dir/build/$1/cli}"
    shift

    echo "Output folder: $builddir"

    local options=(
        "-DCMAKE_BUILD_TYPE=Debug"
        "-DI15DOT4_IEEE_EUI64="
        "-DOT_APP_NCP=OFF"
        "-DOT_APP_CLI=ON"
        "-DOT_APP_RCP=OFF"
        "-DOT_BORDER_ROUTER=ON"
        "-DOT_COAP=ON"
        "-DOT_COAPS=ON"
        "-DOT_COMMISSIONER=ON"
        "-DOT_CSL_AUTO_SYNC=OFF"
        "-DOT_CSL_RECEIVER=ON"
        "-DOT_DHCP6_CLIENT=ON"
        "-DOT_DNS_CLIENT=ON"
        "-DOT_DUA=ON"
        "-DOT_ECDSA=ON"
        "-DOT_FTD=ON"
        "-DOT_JOINER=ON"
        "-DOT_LINK_METRICS_INITIATOR=ON"
        "-DOT_LINK_METRICS_SUBJECT=ON"
        "-DOT_LOG_LEVEL=CRIT"
        "-DOT_MAC_FILTER=ON"
        "-DOT_MLR=ON"
        "-DOT_PLATFORM=external"
        "-DOT_RCP=OFF"
        "-DOT_SLAAC=ON"
        "-DOT_SRP_CLIENT=ON"
        "-DOT_THREAD_VERSION=1.3.1"
    )

    options+=("-DCMAKE_TOOLCHAIN_FILE=src/${target_platform}/arm-none-eabi.cmake")

    cmake -GNinja -S "${repo_dir}" -B "${builddir}" "$@" "${options[@]}"
    cmake --build "${builddir}" --target "${OT_CMAKE_NINJA_TARGET[@]}"
}

build_ncp_uart()
{
    # Create the output folder
    builddir="${OT_CMAKE_BUILD_DIR:-$repo_dir/build/$1/ncp}"
    shift

    echo "Output folder: $builddir"

    local options=(
        "-DCMAKE_BUILD_TYPE=Debug"
        "-DI15DOT4_IEEE_EUI64="
        "-DOT_APP_NCP=ON"
        "-DOT_APP_CLI=OFF"
        "-DOT_APP_RCP=OFF"
        "-DOT_BORDER_ROUTER=ON"
        "-DOT_COAP=ON"
        "-DOT_COAPS=ON"
        "-DOT_COMMISSIONER=ON"
        "-DOT_CSL_RECEIVER=ON"
        "-DOT_DHCP6_CLIENT=ON"
        "-DOT_DNS_CLIENT=ON"
        "-DOT_DUA=ON"
        "-DOT_ECDSA=ON"
        "-DOT_FTD=ON"
        "-DOT_JOINER=ON"
        "-DOT_LINK_METRICS_INITIATOR=ON"
        "-DOT_LINK_METRICS_SUBJECT=ON"
        "-DOT_LOG_LEVEL=CRIT"
        "-DOT_MAC_FILTER=ON"
        "-DOT_MLR=ON"
        "-DOT_PLATFORM=external"
        "-DOT_RCP=OFF"
        "-DOT_SLAAC=ON"
        "-DOT_SRP_CLIENT=ON"
        "-DOT_THREAD_VERSION=1.3.1"
    )

    options+=("-DCMAKE_TOOLCHAIN_FILE=src/${target_platform}/arm-none-eabi.cmake")

    cmake -GNinja -S "${repo_dir}" -B "${builddir}" "$@" "${options[@]}"
    cmake --build "${builddir}" --target "${OT_CMAKE_NINJA_TARGET[@]}"
}

# Utility to build OpenThread RCP
build_rcp_uart()
{
    # Create the output folder
    builddir="${OT_CMAKE_BUILD_DIR:-$repo_dir/build/$1/rcp}"
    shift

    echo "Output folder: $builddir"

    local options=(
        "-DCMAKE_BUILD_TYPE=Debug"
        "-DI15DOT4_IEEE_EUI64="
        "-DOT_APP_CLI=OFF"
        "-DOT_APP_NCP=OFF"
        "-DOT_APP_RCP=ON"
        "-DOT_COMPILE_WARNING_AS_ERROR=ON"
        "-DOT_FTD=OFF"
        "-DOT_LOG_LEVEL=CRIT"
        "-DOT_MTD=OFF"
        "-DOT_PLATFORM=external"
        "-DOT_RCP=ON"
        "-DOT_THREAD_VERSION=1.3.1"
    )

    options+=("-DCMAKE_TOOLCHAIN_FILE=src/${target_platform}/arm-none-eabi.cmake")

    cmake -GNinja -S "${repo_dir}" -B "${builddir}" "$@" "${options[@]}"
    cmake --build "${builddir}" --target "${OT_CMAKE_NINJA_TARGET[@]}"
}

main()
{
    # Read target platform.
    local target_platform="$1"

    # Read target board
    shift
    local target_board="$1"

    # Read target chipset
    shift
    local target_chipset="$1"

    # Read target app
    shift
    local target_app="$1"

    # Read build options from command line
    shift
    local cmdline_options=("$@")

    echo "Building $target_board $target_app"
    echo "User specified build options: ${cmdline_options[*]}"
    echo "General options: ${options[*]}}"
    if [ "$target_app" == "cli" ]; then
        read -r -a OT_CMAKE_NINJA_TARGET < <(echo "${OT_CMAKE_NINJA_TARGET:-cli-ftd cli-mtd}")
        build_cli_uart "$target_board" -DOT_BUILD_EXECUTABLES=OFF -DIFX_PLATFORM="$target_platform" -DIFX_CHIPSET="$target_chipset" -DIFX_BOARD="$target_board" "${cmdline_options[@]}"
        unset OT_CMAKE_NINJA_TARGET
    elif [ "$target_app" == "ncp" ]; then
        read -r -a OT_CMAKE_NINJA_TARGET < <(echo "${OT_CMAKE_NINJA_TARGET:-ncp-ftd ncp-mtd}")
        build_ncp_uart "$target_board" -DOT_BUILD_EXECUTABLES=OFF -DIFX_PLATFORM="$target_platform" -DIFX_CHIPSET="$target_chipset" -DIFX_BOARD="$target_board" "${cmdline_options[@]}"
        unset OT_CMAKE_NINJA_TARGET
    elif [ "$target_app" == "rcp" ]; then
        read -r -a OT_CMAKE_NINJA_TARGET < <(echo "${OT_CMAKE_NINJA_TARGET:-rcp}")
        build_rcp_uart "$target_board" -DOT_BUILD_EXECUTABLES=OFF -DIFX_PLATFORM="$target_platform" -DIFX_CHIPSET="$target_chipset" -DIFX_BOARD="$target_board" "${cmdline_options[@]}"
        unset OT_CMAKE_NINJA_TARGET
    fi
}

###################################################################################################
#
# Program Start
#
###################################################################################################

set -euxo pipefail

# Parse input parameters
target_platform=''
target_chipset=''
target_board=''
target_app=''
cmdline_options=()
declare -a ifx_platform=()
platform_dir="$(pwd)"/third_party/infineon/platform

if [[ $# == 0 ]]; then
    # Load available platforms
    available_platforms_load ifx_platform "$platform_dir"
    echo "Available Platforms: ${ifx_platform[*]}"

    # Load available chipsets
    for target_platform in "${ifx_platform[@]}"; do
        chipsets=()
        target_platform_dir="$platform_dir"/"$target_platform"

        if [[ $target_platform == "cyw"* ]]; then # lead by "cyw"
            chipset_group=${target_platform:3}

            available_chipset_load chipsets "$target_platform_dir" "$chipset_group"
            echo "Available Chipsets for ${target_platform}: ${chipsets[*]}"

            # Load available board for target chipset
            boards=()
            for target_chip in "${chipsets[@]}"; do
                if [[ $target_chip == "30739a0" ]]; then # special case: 30739a0
                    chispset_name="930739"
                else
                    chispset_name="$target_chip"
                fi

                target_bsp_dir="$platform_dir"/"$target_platform"/bsp
                available_boards_load boards "$target_bsp_dir" "$chispset_name"
                echo "Available boards for ${target_chip}: ${boards[*]}"
            done
        fi
    done

    available_apps_load

    die "Please used platform=WWW chipset=XXX board=YYY app=ZZZ to specifiy target board or use make all to build all available executables."
elif [[ $1 == "all" ]]; then # Build all supported platforms with all supported boards
    # Parse command line options
    shift
    cmdline_options+=("$@")

    available_apps_load

    # Load available platforms
    available_platforms_load ifx_platform "$platform_dir"
    echo "Available Platforms: ${ifx_platform[*]}"

    for target_platform in "${ifx_platform[@]}"; do
        chipsets=()
        target_platform_dir="$platform_dir"/"$target_platform"

        if [[ $target_platform == "cyw"* ]]; then # lead by "cyw"
            chipset_group=${target_platform:3}

            available_chipset_load chipsets "$target_platform_dir" "$chipset_group"

            # Load available board for target chipset
            boards=()
            for target_chip in "${chipsets[@]}"; do
                if [[ $target_chip == "30739a0" ]]; then # special case: 30739a0
                    chispset_name="930739"
                else
                    chispset_name="$target_chip"
                fi

                target_bsp_dir="$platform_dir"/"$target_platform"/bsp
                available_boards_load boards "$target_bsp_dir" "$chispset_name"
                echo "Available boards for ${target_chip}: ${boards[*]}"

                for target_board in "${boards[@]}"; do
                    for target_app in "${IFX_APPS[@]}"; do
                        main "$target_platform" "$target_board" "$target_chip" "$target_app" "${cmdline_options[@]}"
                    done
                done
            done
        fi
    done
else
    # Build specified platform with specified board
    sub_string_platform="platform="
    sub_string_chipset="chipset="
    sub_string_board="board="
    sub_string_app="app="
    for param in "$@"; do
        if [[ $param == "$sub_string_platform"* ]]; then
            target_platform=${param##"$sub_string_platform"}
        elif [[ $param == "$sub_string_chipset"* ]]; then
            target_chipset=${param##"$sub_string_chipset"}
        elif [[ $param == "$sub_string_board"* ]]; then
            target_board=${param##"$sub_string_board"}
        elif [[ $param == "$sub_string_app"* ]]; then
            target_app=${param##"$sub_string_app"}
        else
            cmdline_options+=("$param")
        fi
    done

    # Check if target platform has been assigned
    if [ -z "$target_platform" ]; then
        die "target platform has not been assigned"
    fi

    # Load available platforms
    available_platforms_load ifx_platform "$platform_dir"

    echo $target_platform

    # Check if the target platform is available
    echo "${ifx_platform[@]}" | grep -wq "$target_platform" || die "Unsupported platform $target_platform"

    # Check if target chipset has been assigned
    if [ -z "$target_chipset" ]; then
        die "target chipset has not been assigned"
    fi

    # Check if the target chipset is available
    chipsets=()
    target_platform_dir="$platform_dir"/"$target_platform"

    if [[ $target_platform == "cyw"* ]]; then # lead by "cyw"
        chipset_group=${target_platform:3}

        available_chipset_load chipsets "$target_platform_dir" "$chipset_group"

        echo "${chipsets[@]}" | grep -wq "$target_chipset" || die "Unsupported chipset $target_chipset"
    fi

    # Check if target board has been assigned
    if [ -z "$target_board" ]; then
        die "target board has not been assigned"
    fi

    # Check if the target board is available
    boards=()
    target_bsp_dir="$platform_dir"/"$target_platform"/bsp

    if [[ $target_chipset == "30739a0" ]]; then # special case: 30739a0
        chispset_name="930739"
    else
        chispset_name="$target_chipset"
    fi

    available_boards_load boards "$target_bsp_dir" "$chispset_name"
    echo "${boards[@]}" | grep -wq "${target_board}" || die "Unsupported board $target_board for $target_chipset"

    # Check if target app has been assigned
    if [ -z "$target_app" ]; then
        die "target app has not been assigned"
    fi

    # Check if the target app is available
    available_apps_load
    echo "${IFX_APPS[@]}" | grep -wq "${target_app}" || die "Unsupported app $target_app"

    main "$target_platform" "$target_board" "$target_chipset" "$target_app" "${cmdline_options[@]}"
fi
